package llama.network;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.IOException;
import java.util.Date;
import java.util.ListIterator;

import llama.constants.DefaultTags;
import llama.core.Contact;
import llama.core.ContactList;
import llama.core.IUser;
import llama.core.LoginCredentials;
import llama.core.Message;
import llama.core.ORMLiteUser;
import llama.core.SearchTerm;
import llama.core.UserList;

/**
 * This class simulates an active IServerConnection providing possibility to run tests without a Server.
 */
public class MockServerConnection implements IServerConnection {
	private static final IUser MOCK_ACTIVE_USER = new ORMLiteUser("", "", "kalle@mail.com", "");
	private static final IUser MOCK_CONTACT_USER = new ORMLiteUser("Dummy", "Dumb", "dummy@mail.com", "");
	
	private PropertyChangeSupport pcs;
	private boolean connected;
	private final ContactList contactList = new ContactList();
	private ContactList workingCopyContactList = new ContactList();
	
	public MockServerConnection() {
		pcs = new PropertyChangeSupport(this);

		//Mock Contacts
		contactList.add(new Contact(new ORMLiteUser("Karl", "Andersson", "kalle@mail.com", ""), "Friends"));
		contactList.add(new Contact(new ORMLiteUser("Anders", "Andersson", "anders@asdf.com", ""), "Friends"));
		contactList.add(new Contact(new ORMLiteUser("Charlie", "Day", "charlie@asiphilly.com", ""), "Friends"));
		contactList.add(new Contact(new ORMLiteUser("Glenn-\u00C5ke", "Gl\u00F6m", "glenn-ake@mail.com", ""), "Mortal Enemies"));
		
		workingCopyContactList = (ContactList) contactList.clone();
	}
	
	
	@Override
	public void connect(int timeout, String host, int tcpPort) throws IOException {
		connected = true;
	}

	@Override
	public boolean isConnected() {
		return connected;
	}
	
	@Override
	public void addPropertyChangeListener(PropertyChangeListener pcl) {
		pcs.addPropertyChangeListener(pcl);

	}

	@Override
	public void removePropertyChangeListener(PropertyChangeListener pcl) {
		pcs.removePropertyChangeListener(pcl);
	}

	@Override
	public void send(NetworkMessage networkMsg) {
		switch (networkMsg.getType()) {
		case LOGIN:
			pcs.firePropertyChange(mockLoginSuccess());
			pcs.firePropertyChange(mockContactList());
			break;
		case MESSAGE:
			pcs.firePropertyChange(mockMessage(networkMsg));
			pcs.firePropertyChange(mockMessage(new NetworkMessage
					(new Message("dummy", MOCK_CONTACT_USER, MOCK_ACTIVE_USER,
							new Date(System.currentTimeMillis())),
						NetworkMessage.Type.MESSAGE)));
			break;
		case ADD_CONTACT:
			pcs.firePropertyChange(mockAddContact(networkMsg));
			break;
		case REMOVE_CONTACT:
			pcs.firePropertyChange(mockRemoveContact(networkMsg));
			break;
		case SEARCH_TERM:
			pcs.firePropertyChange(mockSearchUser(networkMsg));
			break;
		case ASSIGN_TAG:
			pcs.firePropertyChange(mockAssignTag(networkMsg));
			break;
		}
	}

	private PropertyChangeEvent mockAssignTag(NetworkMessage networkMsg) {
		Contact contact = (Contact) networkMsg.getObject();
		ContactList contactList = workingCopyContactList;
		
		ListIterator<Contact> listIterator = contactList.listIterator();
		while(listIterator.hasNext()) {
			Contact tempContact = listIterator.next();
			if(tempContact.equals(contact)) {
				tempContact.setTag(contact.getTag());
			}
		}
		
		return new PropertyChangeEvent(this, "Mock Tag Contact List", null, new NetworkMessage(contactList, NetworkMessage.Type.NEW_CONTACT_LIST));
	}


	private PropertyChangeEvent mockRemoveContact(NetworkMessage nm) {
		IUser user = (IUser) nm.getObject();
		ContactList list = workingCopyContactList;
		
		ListIterator<Contact> listIterator = list.listIterator();
		while(listIterator.hasNext()) {
			Contact tempContact = listIterator.next();
			if(tempContact.getUser().equals(user)) {
				listIterator.remove();
				break;
			}
		}
		
		return new PropertyChangeEvent(this, "Mock Contact List", null, new NetworkMessage(list, NetworkMessage.Type.NEW_CONTACT_LIST));
	}


	private PropertyChangeEvent mockSearchUser(NetworkMessage nm) {
		SearchTerm searchTerm = (SearchTerm) nm.getObject();
		String term = searchTerm.getTerm();
		ContactList contactList = this.contactList;
		UserList userlist = new UserList();
		
		
		ListIterator<Contact> listIterator = contactList.listIterator();
		while(listIterator.hasNext()) {
			Contact tempContact = listIterator.next();
			if(tempContact.getUser().getEmail().indexOf(term) >= 0 || tempContact.getUser().getFullName().indexOf(term) >= 0) {
				userlist.add(tempContact.getUser());
			}
		}
		
		return new PropertyChangeEvent(this, "Mock Search Resuluts", null, new NetworkMessage(userlist, NetworkMessage.Type.SEARCH_RESULTS));
	}


	private PropertyChangeEvent mockAddContact(NetworkMessage nm) {
		IUser user = (IUser) nm.getObject();
		System.out.println("Adding: "+user.getFullName());
		
		Contact contact = new Contact(user, DefaultTags.DEFAULT_TAG);
		workingCopyContactList.add(contact);
		
		return new PropertyChangeEvent(this, "Mock Contact List", null, new NetworkMessage(workingCopyContactList, NetworkMessage.Type.NEW_CONTACT_LIST));
	}


	@Override
	public void authenticate(LoginCredentials o) {
		//Do nothing

	}

	@Override
	public void disconnect() {
		connected = false;
	}
	
	private PropertyChangeEvent mockMessage(NetworkMessage networkMsg) {
		return new PropertyChangeEvent(this, "Mock Message Return", null, networkMsg);
	}
	
	private PropertyChangeEvent mockLoginSuccess() {
		return new PropertyChangeEvent(this, "Mock Login Success", null, new NetworkMessage(new ORMLiteUser("Kalle", "Johansson", MOCK_ACTIVE_USER.getEmail(), ""), NetworkMessage.Type.LOGIN_SUCCESS));
	}
	
	private PropertyChangeEvent mockContactList() {
		ContactList list = workingCopyContactList;
		
		return new PropertyChangeEvent(this, "Mock Contact List", null, new NetworkMessage(list, NetworkMessage.Type.NEW_CONTACT_LIST));
	}
}
